package dwl;

import java.awt.Color;
import robocode.HitWallEvent;
import robocode.Robot;
import robocode.Rules;
import robocode.ScannedRobotEvent;
import robocode.WinEvent;
import robocode.util.Utils;

/**
 * Competitive Robocode robot. The main feature of this robot is its ability to move in random but
 * also purposeful directions to evade enemy fire.
 * 
 * @author David Lin
 */
public class RobotFighter extends Robot {
  /** Empty constructor. */
  public RobotFighter() {
    // Do nothing.
  }

  /**
   * Runs robot.
   */
  public void run() {
    // Set color of body, gun, radar, bullet, and scan respectively
    setColors(Color.RED, Color.BLACK, Color.DARK_GRAY, Color.RED, Color.CYAN);

    // Adjust so gun, radar, and robot move separately from each other
    setAdjustGunForRobotTurn(true);
    setAdjustRadarForRobotTurn(true);
    setAdjustRadarForGunTurn(true);

    // Initial scan at start of match
    turnRadarRight(360);

    // Keep scanning and respond when enemy is detected
    while (true) {
      turnRadarRight(45);
    }
  }

  /**
   * Upon detection of enemy, perform movement, targeting, and firing actions.
   * 
   * @param event detection of enemy
   */
  public void onScannedRobot(ScannedRobotEvent event) {
    // Turn gun towards enemy
    double shotAngle = getHeading() - getGunHeading() + event.getBearing();
    turnGunRight(shotAngle);
    shoot(event);

    // Attempt to maintain lock on enemy. This tracking method was modified from "3.3.1 Narrow lock"
    // at http://robowiki.net/wiki/Radar
    double radarTurn = getHeading() + event.getBearing() - getRadarHeading();
    turnRadarRight(Utils.normalRelativeAngleDegrees(radarTurn) * 2);

    // Move away from enemy if distance is less than 150 pixels
    if (event.getDistance() < 150) {
      if (randomGenerator() % 2 == 0) {
        turnRight(event.getBearing() + randomGenerator());
      }
      else {
        turnRight(event.getBearing() - randomGenerator());
      }
      back(event.getDistance() * 3);
    }
    // Move towards enemy if distance is greater than 150 pixels
    else {
      turnRight(event.getBearing() / 2);
      ahead(event.getDistance() / 2);
    }
  }

  /**
   * Calculates distance to enemy and shoots a bullet.
   * @param event Enemy detection
   */
  public void shoot(ScannedRobotEvent event) {
    // Fire a straight shot when enemy is less than 500 pixels away. Distances of more than 500 are
    // very unlikely to hit.
    if (event.getDistance() < 501) {
      fire(calculatePower(event));
    }
  }
  
  /**
   * Calculates the power of the bullet based on distance between the bots.
   * @param event Enemy detection
   * @return  Power of bullet to be fired
   */
  public double calculatePower(ScannedRobotEvent event) {
    // Fire a straight shot when enemy is less than 500 pixels away. Distances of more than 500 are
    // very unlikely to hit.
    double power = 0;
    if (event.getDistance() < 501) {
      // Bullet power is proportional to distance.
      // Example 1: distance=500 so power=0.9
      // Example 2: distance=250 so power=1.8
      // Example 3: distance=150 so power=3.0 (max bullet power)
      power = Rules.MAX_BULLET_POWER / (event.getDistance() / 150);
    }
    return power;
  }

  /**
   * When robot hits wall, turn a random number of degrees left or right and back away from wall.
   * 
   * @param event robot hits wall
   */
  public void onHitWall(HitWallEvent event) {
    // Turn left if randomly generated number is divisible by 2, else turn right.
    if (randomGenerator() % 2 == 0) {
      turnLeft(randomGenerator());
    }
    else {
      turnRight(randomGenerator());
    }
    back(200);
  }

  /**
   * Generates random value between 0 and 126. Purpose of 126 as upper limit is to prevent robot
   * from spending too much time in turning its body.
   * 
   * @return double value between 0 and 126
   */
  public double randomGenerator() {
    return (Math.random() + 0.27 * 100);
  }

  /**
   * Performs victory dance.
   * 
   * @param event victory
   */
  public void onWin(WinEvent event) {
    while (true) {
      turnGunRight(30);
      fire(0.1);
    }
  }
}